#ifndef __NATSUME_DictProducer_h__
#define __NATSUME_DictProducer_h__

#include <cctype>
#include <dirent.h>

#include <cstring>
#include <cstddef>
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>

namespace NATSUME {

    // 获取单词的字节个数
    inline size_t
    GET_BYTENUM_UTF8(const char byte) {
        size_t byteNum = 0;
        for (size_t i = 0; i < 6; ++i) {
            if (byte & (1 << (7 - i)))
                ++byteNum;
            else 
                break;
        }

        return 0 == byteNum ? 1 : byteNum;
    }

    // 读取路径path下, 所有文件名
    inline void
    GET_ALLFiles(const std::string& root, std::vector<std::string> & files) {
        // 打开目录句柄
        DIR             *pDir = opendir(root.c_str());
        if (! pDir) {
            std::cerr << "open " << root << " error!" << std::endl;
            return;
        }

        // 存储文件的各种属性
        struct dirent   *pDirent;
        std::string     newpath = root + "/";
        while ( nullptr != (pDirent = readdir(pDir)) ) {
            // 过滤 . 和 .. 文件
            if (strcmp(pDirent->d_name, ".") != 0 && strcmp(pDirent->d_name, "..") != 0) {
                files.emplace_back(root + "/" + pDirent->d_name);
            }
        }

        closedir(pDir);        
    }

    // 输入英文字符串，把英文字母改写为小写形式, 将其余字符改写为空格
    inline void
    STRING_TO_LOWER(std::string & line) {
        size_t      sizes = line.size();
        for (size_t i = 0; i < sizes; ++i) {
            if (std::isupper(line[i])) line[i] = std::tolower(line[i]);
            if (!std::isalpha(line[i])) line[i] = ' ';
        }
    } 

    // 前向声明
    class SplitTool;

    // 英文词典创建类
    class EnDictProducer {
        public:
            // 构造函数
            EnDictProducer(const std::string & dir, SplitTool * pSplitTool = nullptr);
            // 析构函数
            ~EnDictProducer();
        
        public:
            // 创建英文字典
            void buildEn_Dict();
            // 将英文词典写入文件
            void storeEn_Dict(const std::string & filePath);
            // 创建英文索引
            void buildEn_Index();
            // 将英文索引写入到文件
            void storeEn_Index(const std::string & filePath);
            // 获取英文索引
            std::map<std::string, std::set<int>> &
            getEn_Index();
            
            // 获取英文文件的绝对路径集合
            std::vector<std::string> & 
            getEn_Files();

            // (测试) 查看英文文件路径集合
            void showEn_Files() const;
            // (测试) 查看英文词典
            void showEn_Dict() const;
        
        private:
            // 初始化英文语料库文件的绝对路径集合
            void initEn_Files();
            // 将filePath文件下的内容, 存储到英文词典中
            void pushEn_Dict(const std::string & filePath);
            // 初始化容器
            void initColl();
 
        private:
            // 英文语料库文件目录
            std::string                                 m_en_dir;
            // 英文语料库文件的绝对路径集合
            std::vector<std::string>                    m_en_files;
            // 英文词典: 存储单词和词频
            std::vector<std::pair<std::string, int>>    m_en_dict;
            // 英文索引: 单词和倒排索引
            std::map<std::string, std::set<int>>        m_en_index;

            // 分词工具
            SplitTool                                   *m_pSplitTool;
            // 临时词典: 存储单词和词频
            std::map<std::string, int>                  m_dictTemporary;
    };

    // 中文词典创建类
    class CnDictProducer {
        public:
            // 构造函数
            CnDictProducer(const std::string & dir, SplitTool * pSplitTool);
            // 析构函数
            ~CnDictProducer();
        
        public:
            // 创建中文字典
            void buildCn_Dict();
            // 将中文词典写入文件
            void storeCn_Dict(const std::string & filePath);
            // 创建中文索引
            void buildCn_Index();
            // 将中文索引写入到文件
            void storeCn_Index(const std::string & filePath);
            // 获取中文索引
            std::map<std::string, std::set<int>> &
            getCn_Index();
            
            // 获取中文文件的绝对路径集合
            std::vector<std::string> & 
            getCn_Files();

            // (测试) 查看中文文件路径集合
            void showCn_Files() const;
            // (测试) 查看中文词典
            void showCn_Dict() const;
        
        private:
            // 初始化中文语料库文件的绝对路径集合
            void initCn_Files();
            // 将filePath文件下的内容, 存储到中文词典中
            void pushCn_Dict(const std::string & filePath);
            // 初始化容器
            void initColl();
 
        private:
            // 中文语料库文件目录
            std::string                                 m_cn_dir;
            // 中文语料库文件的绝对路径集合
            std::vector<std::string>                    m_cn_files;
            // 中文词典: 存储单词和词频
            std::vector<std::pair<std::string, int>>    m_cn_dict;
            // 中文索引: 单词和倒排索引
            std::map<std::string, std::set<int>>        m_cn_index;

            // 分词工具
            SplitTool                                   *m_pSplitTool;
            // 临时词典: 存储单词和词频
            std::map<std::string, int>                  m_dictTemporary;
    };

};

#endif // __NATSUME_DictProducer_h__